﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace EffiProz.Core.Lib.Tar
{
    public class PIFGenerator : MemoryStream
    {
        StreamWriter writer;
        String name;
        int fakePid;    // Only used by contructors
        //char typeFlag;

        public String getName()
        {
            return name;
        }

        protected PIFGenerator()
        {

            try
            {
                writer = new StreamWriter(this, Encoding.UTF8);
            }
            catch (Exception uee)
            {
                throw new Exception(
                    "Serious problem.  can't encode UTF-8", uee);
            }

            fakePid = (int)(DateTime.Now.Ticks % 100000L);

            // Java doesn't have access to PIDs, as PIF wants in the "name" field,
            // so we emulate one in a way that is easy for us.
        }

        /**
         * Construct a PIFGenerator object for a 'g' record.
         *
         * @param sequenceNum  Index starts at 1 in each Tar file
         */
        public PIFGenerator(int sequenceNum)
            : this()
        {

            if (sequenceNum < 1)
            {

                // No need to localize.  Would be caught at dev-time.
                throw new ArgumentException("Sequence numbers start at 1");
            }

            //typeFlag = 'g';
            name = Path.GetTempPath() + "/GlobalHead." + fakePid
                   + '.' + sequenceNum;
        }

        /**
         * Construct a PIFGenerator object for a 'x' record.
         *
         * @param file Target file of the x record.
         */
        public PIFGenerator(FileInfo file)
            : this()
        {

            //typeFlag = 'x';

            String parentPath = (file.Directory == null) ? "." : file.Directory.FullName;

            name = parentPath + "/PaxHeaders." + fakePid + '/' + file.Name;
        }

        /**
         * Convenience wrapper for addRecord(String, String).
         * N.b. this writes values exactly as either "true" or "false".
         *
         * @see #addRecord(String, String)
         * @see Boolean#toString(bool)
         */
        public void addRecord(String key,
                              bool b)
        {
            addRecord(key, b.ToString());
        }

        /**
         * Convenience wrapper for addRecord(String, String).
         *
         * @see #addRecord(String, String)
         */
        public void addRecord(String key,
                              int i)
        {
            addRecord(key, i.ToString());
        }

        /**
         * Convenience wrapper for addRecord(String, String).
         *
         * @see #addRecord(String, String)
         */
        public void addRecord(String key,
                              long l)
        {
            addRecord(key, l.ToString());
        }

        /**
         * I guess the "initial length" field is supposed to be in units of
         * characters, not bytes?
         */
        public void addRecord(String key,
                              String value)
        {

            if (key == null || value == null || key.Length < 1
                    || value.Length < 1)
            {
                throw new TarMalformatException(
                    RB.singleton.getString(RB.ZERO_WRITE));
            }

            int lenWithoutIlen = key.Length + value.Length + 3;

            // "Ilen" means Initial Length field.  +3 = SPACE + = + \n
            int lenW = 0;    // lenW = Length With initial-length-field

            if (lenWithoutIlen < 8)
            {
                lenW = lenWithoutIlen + 1;    // Takes just 1 char to report total
            }
            else if (lenWithoutIlen < 97)
            {
                lenW = lenWithoutIlen + 2;    // Takes 2 chars to report this total
            }
            else if (lenWithoutIlen < 996)
            {
                lenW = lenWithoutIlen + 3;    // Takes 3...
            }
            else if (lenWithoutIlen < 9995)
            {
                lenW = lenWithoutIlen + 4;    // ditto
            }
            else if (lenWithoutIlen < 99994)
            {
                lenW = lenWithoutIlen + 5;
            }
            else
            {
                throw new TarMalformatException(
                    RB.singleton.getString(RB.PIF_TOOBIG, 99991));
            }

            writer.Write(lenW.ToString());
            writer.Write(' ');
            writer.Write(key);
            writer.Write('=');
            writer.Write(value);
            writer.Write('\n');
            writer.Flush();    // Does this do anything with a BAOS?
        }
    }
}
